package com.jade.bss.ec.order.impl;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import com.jade.bss.ec.order.ECOrder;
import com.jade.bss.ec.order.OrderDao;
import com.jade.bss.ec.order.OrderException;
import com.jade.framework.base.criterion.Criteria;
import com.jade.framework.base.criterion.Restrictions;
import com.jade.framework.base.criterion.sql.SqlUtils;
import com.jade.framework.base.util.PagingList;
import com.jade.framework.base.util.Parameters;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;

/**
 * Created by dwzhang on 16/1/14.
 */
public class JpaOrderDao
        implements OrderDao
{
    private static final String SQL = "SELECT ecorder FROM com.jade.bss.ec.order.ECOrder ecorder";
    @PersistenceContext (unitName = "default")
    protected EntityManager em;

    @Caching (evict = {@CacheEvict (value = "bss.ecorder.g", key = "#order.id"),
            @CacheEvict (value = "bss.ecorder.qc", key = "#order.ownerType + '_' + #order.ownerId + '[%GRP%]'"),
            @CacheEvict (value = "bss.ecorder.q", allEntries = true)})
    public void add(ECOrder order)
            throws OrderException
    {
        em.persist(order);
    }

    @Caching (evict = {@CacheEvict (value = "bss.ecorder.g", key = "#order.id"),
            @CacheEvict (value = "bss.ecorder.qc", key = "#order.ownerType + '_' + #order.ownerId + '[%GRP%]'"),
            @CacheEvict (value = "bss.ecorder.q", allEntries = true)})
    public void update(ECOrder order)
            throws OrderException
    {
        em.merge(order);
    }

    @Caching (evict = {@CacheEvict (value = "bss.ecorder.g", key = "#order.id"),
            @CacheEvict (value = "bss.ecorder.qc", key = "#order.ownerType + '_' + #order.ownerId + '[%GRP%]'"),
            @CacheEvict (value = "bss.ecorder.q", allEntries = true)})
    public int update(ECOrder order, Parameters params, int[] statuses)
            throws OrderException
    {
        params.remove("id");
        if (params.isEmpty()) {
            throw new IllegalArgumentException("There is one field at least to update");
        }

        StringBuilder hsql = new StringBuilder();
        hsql.append("UPDATE com.jade.bss.ec.order.ECOrder SET ");
        Iterator<String> names = params.getNames();
        while (names.hasNext()) {
            String name = names.next();
            hsql.append(name).append("=:").append(name);
            if (names.hasNext()) {
                hsql.append(", ");
            } else {
                hsql.append(" ");
            }
        }
        hsql.append("WHERE id=:id ");
        if (statuses != null && statuses.length > 0) {
            hsql.append("AND status in :oldStatus");
        }

        Query query = em.createQuery(hsql.toString());
        names = params.getNames();
        while (names.hasNext()) {
            String name = names.next();
            query.setParameter(name, params.getObject(name));
        }
        if (statuses != null && statuses.length > 0) {
            List<Integer> list = new ArrayList<Integer>();
            for (int status : statuses) {
                list.add(status);
            }
            query.setParameter("oldStatus", list);
        }
        query.setParameter("id", order.getId());
        return query.executeUpdate();
    }

    @Caching (evict = {@CacheEvict (value = "bss.ecorder.g", key = "#order.id"),
            @CacheEvict (value = "bss.ecorder.qc", key = "#order.ownerType + '_' + #order.ownerId + '[%GRP%]'"),
            @CacheEvict (value = "bss.ecorder.q", allEntries = true)})
    public void remove(ECOrder order)
            throws OrderException
    {
        ECOrder old = em.find(ECOrder.class, order.getId());
        if (old != null) {
            em.remove(old);
        }
    }

    @Cacheable (value = "bss.ecorder.g", key = "#id")
    public ECOrder get(long id)
            throws OrderException
    {
        return em.find(ECOrder.class, id);
    }

    @Cacheable (value = "bss.ecorder.qc", key = "#ownerType + '_' + #ownerId + '[%GRP%]' + #criteria")
    public PagingList<ECOrder> query(String ownerType, String ownerId, Criteria criteria)
    {
        criteria.add(Restrictions.eq("ecorder.ownerType", ownerType));
        criteria.add(Restrictions.eq("ecorder.ownerId", ownerId));
        return query(criteria);
    }

    @Cacheable (value = "bss.ecorder.q", key = "#criteria")
    public PagingList<ECOrder> query(Criteria criteria)
    {
        return SqlUtils.sqlQuery(SQL, em, criteria);
    }
}
